{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 教程: 隐私深度学习的基础工具\n",
    "\n",
    "欢迎使用PySyft的入门教程，了解隐私保护与分布式深度学习。 本系列笔记本是逐步指南，可让您了解对秘密/私有数据/模型进行深度学习所需的新工具和技术，而无需将它们集中在一个权威下（译者注：通常的深度学习模型训练是将数据集中在一台机器上进行的）。\n",
    "\n",
    "**范围:** 请注意，我们不仅要讨论如何分散数据/加密数据，还要解决如何使用PySyft帮助分散数据周围的整个环境，甚至包括存储和查询数据的数据库， 以及用于从数据中提取信息的神经网络模型。 创建新的PySyft扩展后，这些笔记本将通过新教程进行扩展，以解释新功能。\n",
    "\n",
    "作者:\n",
    "- Andrew Trask - Twitter: [@iamtrask](https://twitter.com/iamtrask)\n",
    "\n",
    "中文版译者：\n",
    "- Hou Wei - github：[@dljgs1](https://github.com/dljgs1)\n",
    "\n",
    "\n",
    "\n",
    "## 大纲:\n",
    "\n",
    "- 第一部分: 隐私深度学习的基础工具\n",
    "\n",
    "\n",
    "## 为什么使用本教程?\n",
    "\n",
    "**1) 职业生涯中的竞争优势** - 在过去的20年中，随着模拟过程的数字化，数字革命已使越来越多的数据可访问。然而, 随着诸如[GDPR](https://eugdpr.org/)之类的新法规发布, 企业面临着减少个人信息使用（更重要的是如何使用）的压力. **底线:** 数据科学家将不会通过“老派”工具访问尽可能多的数据，但是通过学习隐私深度学习工具，您可以领先于这一曲线，并在您的职业生涯中具有竞争优势。\n",
    "\n",
    "**2) 创业机会** - 深度学习可以解决社会上的许多问题，但有许多最重要的问题尚未探讨，因为需要访问有关人的一些极其敏感的信息 (比如用深度学习帮助患精神疾病或者关系问题的人)。因此，学习私有深度学习可以为您释放大量新的启动机会，而这些人以前没有这些工具集就无法获得这些机会。\n",
    "\n",
    "**3) 社会公益** - 深度学习可用于解决现实世界中的各种问题，但是基于*个人信息*的深度学习是*针对人*的深度学习。 学习如何在您不拥有的数据上进行深度学习不仅仅意味着职业或创业机会，它是帮助解决人们生活中一些最个人和最重要问题的机会，并且可以大规模进行。\n",
    "\n",
    "## How do I get extra credit?\n",
    "\n",
    "- Star PySyft on GitHub! - [https://github.com/OpenMined/PySyft](https://github.com/OpenMined/PySyft)\n",
    "- Make a Youtube video teaching this notebook!\n",
    "\n",
    "\n",
    "……好，开始吧!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part -1: 先决条件\n",
    "\n",
    "- 了解 PyTorch - 如果不了解可以先看这个教程 http://fast.ai 然后再回来\n",
    "- 阅读PySyft框架的论文 https://arxiv.org/pdf/1811.04017.pdf! 这将为您提供有关PySyft的构造方式的全面背景，这将使得会有更直观的认识。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 0: 安装\n",
    "\n",
    "首先，您需要确保已安装正确的东西。 为此，请转到PySyft的自述文件并按照设置说明进行操作。太长不看系列如下：\n",
    "\n",
    "- Install Python 3.6 or higher\n",
    "- Install PyTorch 1.4\n",
    "- pip install syft[udacity]\n",
    "\n",
    "如果哪一步出错了或者不起作用 - 首先阅读 [README](https://github.com/OpenMined/PySyft.git) 安装帮助，以及发GitHub Issue，或者在我们的slack上通知#beginner 频道！[slack.openmined.org](http://slack.openmined.org/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 运行这个cell看看是否工作正常\n",
    "import sys\n",
    "\n",
    "import torch\n",
    "from torch.nn import Parameter\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "import syft as sy\n",
    "hook = sy.TorchHook(torch)\n",
    "\n",
    "torch.tensor([1,2,3,4,5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果执行了此单元格，那么您就可以开跑了了！出发！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 1: 隐私、分布式数据科学的基础工具\n",
    "\n",
    "您想知道的第一个问题可能是：我们如何在无法访问的数据上训练模型？ \n",
    "\n",
    "答案很简单。如果您习惯用Pytorch，那应该很熟悉Torch.Tensor对象，如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5])\n",
    "y = x + x\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "显然，使用这些超级花哨（且功能强大）的张量很重要，但也需要您将数据保存在本地计算机上。这是我们旅程的起点。\n",
    "\n",
    "# 1.1 - 把张量发送到Bob的机器上\n",
    "\n",
    "通常我们会在保存数据的机器上执行数据科学/深度学习，而现在我们希望在某些**其他**机器上执行这种计算。 更具体地说，我们不能再简单地假设数据在我们的本地计算机上。\n",
    "\n",
    "因此，我们现在不使用Torch张量，而要使用指向张量的**指针**。 接下来让我告诉你它的含义。首先，我们假装有一个人拥有一台机器——我们称他为鲍勃。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob = sy.VirtualWorker(hook, id=\"bob\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "假设鲍勃的机器在另一个星球上——也许是火星！但是，此刻机器是空的。让我们创建一些数据，以便将其发送给Bob并了解指针！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5])\n",
    "y = torch.tensor([1,1,1,1,1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在，把张量发送给Bob！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr = x.send(bob)\n",
    "y_ptr = y.send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "BOOM! 现在鲍勃有两个张量！不信？你自己看看！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = x_ptr + x_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意一下。当我们调用 `x.send(bob)`时，它返回了一个称为`x_ptr`的新对象。这是我们第一个指向张量的*指针*。张量的指针本身实际上并**不**保存数据。相反，它们仅包含有关存储在另一台机器上的张量（带有数据）的元数据。这些张量的目的是为我们提供一个直观的API，以告诉其他机器使用该张量来计算函数。让我们看一下指针包含的元数据。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "检查它的元数据！\n",
    "\n",
    "指针有两个主要属性：\n",
    "\n",
    "- `x_ptr.location : bob`, location(位置)，对指针指向的位置的引用\n",
    "- `x_ptr.id_at_location : <random integer>`, 张量存储在位置的id\n",
    "\n",
    "它们以以下格式打印： `<id_at_location>@<location>`\n",
    "\n",
    "还有其他更通用的属性：\n",
    "- `x_ptr.id : <random integer>`, 指针张量的ID，它是随机分配的\n",
    "- `x_ptr.owner : \"me\"`, 拥有指针张量的工作机，这里是本地机器，名为“me”（我）\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr.location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob == x_ptr.location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr.id_at_location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr.owner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你可能想知道为什么拥有指针的本地工作机是一个VirtualWorker（虚拟工作机）, 尽管我们没有创建它。\n",
    "有趣的是，就像我们有一个Bob的VirtualWorker对象一样，（默认情况下）我们也总是有一个对象。 当我们调用`hook = sy.TorchHook()`时它会自动创建，因此通常不必自己创建它。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "me = sy.local_worker\n",
    "me"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "me == x_ptr.owner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最后，就像我们可以在张量上调用 .send()一样，我们可以在指向张量的指针上调用.get()来恢复它！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_ptr.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如您所见，Bob不再具有张量！他们已经搬回我们的机器了！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.2 - 使用张量指针\n",
    "\n",
    "因此，从Bob发送和接收张量很棒，当然这绝不是深度学习！我们希望能够对远程张量执行张量_操作_。幸运的是，张量指针使这变得很容易！您可以像使用普通张量一样使用指针！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5]).send(bob)\n",
    "y = torch.tensor([1,1,1,1,1]).send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = x + y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "瞧！\n",
    "\n",
    "在背后，发生了非常有力的事情。不再是x和y在本地计算加法，而是将命令序列化并发送给Bob，由后者执行计算，创建张量z，然后将指向z的指针返回给我们！\n",
    "\n",
    "如果我们在指针上调用.get()，那么我们将把结果返回到我们的机器上！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Torch函数\n",
    "\n",
    "该API已扩展到Torch的所有操作！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = torch.add(x,y)\n",
    "z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 变量（包括反向传播）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5.], requires_grad=True).send(bob)\n",
    "y = torch.tensor([1,1,1,1,1.], requires_grad=True).send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = (x + y).sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z.backward()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = x.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x.grad"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如您所见，该API确实非常灵活，并且能够执行您通常在Torch中对*远程数据* 执行的几乎所有操作。 这为我们更高级的隐私保护协议（例如联邦学习，安全多方计算和差分隐私）奠定了基础！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 恭喜!!! 是时候加入社区了!\n",
    "\n",
    "祝贺您完成本笔记本教程！ 如果您喜欢此方法，并希望加入保护隐私、去中心化AI和AI供应链（数据）所有权的运动，则可以通过以下方式做到这一点！\n",
    "\n",
    "### 给 PySyft 加星\n",
    "\n",
    "帮助我们的社区的最简单方法是仅通过给GitHub存储库加注星标！ 这有助于提高人们对我们正在构建的出色工具的认识。\n",
    "\n",
    "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "### 加入我们的 Slack!\n",
    "\n",
    "保持最新进展的最佳方法是加入我们的社区！ 您可以通过填写以下表格来做到这一点[http://slack.openmined.org](http://slack.openmined.org)\n",
    "\n",
    "### 加入代码项目!\n",
    "\n",
    "对我们的社区做出贡献的最好方法是成为代码贡献者！ 您随时可以转到PySyft GitHub的Issue页面并过滤“projects”。这将向您显示所有概述，选择您可以加入的项目！如果您不想加入项目，但是想做一些编码，则还可以通过搜索标记为“good first issue”的GitHub问题来寻找更多的“一次性”微型项目。\n",
    "\n",
    "- [PySyft Projects](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n",
    "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### 捐赠\n",
    "\n",
    "如果您没有时间为我们的代码库做贡献，但仍想提供支持，那么您也可以成为Open Collective的支持者。所有捐款都将用于我们的网络托管和其他社区支出，例如黑客马拉松和聚会！\n",
    "\n",
    "[OpenMined's Open Collective Page](https://opencollective.com/openmined)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": false,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
